package com.xhwl.centiotdata.utils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.time.temporal.WeekFields;
import java.util.*;

/*
 * @author kingboy
 * @Date 2017/7/22 下午2:12
 * @Description LocalDateTimeUtils is used to Java8中的时间类
 */
public class LocalDateTimeUtils {

    //获取当前时间的LocalDateTime对象
    //LocalDateTime.now();

    //根据年月日构建LocalDateTime
    //LocalDateTime.of();

    //比较日期先后
    //LocalDateTime.now().isBefore(),
    //LocalDateTime.now().isAfter(),

    /**
     * 日期、时间格式
     */
    public static final String YEAR = "yyyy";
    public static final String YEAR_MONTH = "yyyy-MM";
    public static final String YEAR_MONTH_DAY = "yyyy-MM-dd";
    public static final String ID_CARD_TIME = "yyyyMMdd";
    public static final String DATE_HOUR = "yyyy-MM-dd HH";
    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_TIME_STR = "yyyyMMddHHmmss";
    public static final String DATE_TIME_T_STR = "yyyy-MM-dd'T'HH:mm:ss";
    public static final String DATE_TIME_UK_STR = "EEE MMM dd HH:mm:ss Z yyyy";

    //Date转换为LocalDateTime
    public static LocalDateTime convertDateToLDT(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    //LocalDateTime转换为Date
    public static Date convertLDTToDate(LocalDateTime time) {
        return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
    }

    //获取指定日期的毫秒
    public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //获取指定日期的秒
    public static Long getSecondsByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

    //获取指定时间的指定格式
    public static String formatTime(LocalDateTime time,String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    //获取指定时间的指定格式
    public static String formatTime(LocalDate date,String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    //获取当前时间的指定格式
    public static String formatNow(String pattern) {
        return  formatTime(LocalDateTime.now(), pattern);
    }

    //日期加上一个数,根据field不同加不同值,field为ChronoUnit.*
    public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
        return time.plus(number, field);
    }

    //日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*
    public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field){
        return time.minus(number,field);
    }

    /**
     * 获取两个日期的差  field参数为ChronoUnit.*
     * @param startTime
     * @param endTime
     * @param field  单位(年月日时分秒)
     * @return
     */
    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (field == ChronoUnit.MONTHS) {
            return period.getYears() * 12 + period.getMonths();
        }
        return field.between(startTime, endTime);
    }

    //获取一天的开始时间，2017,7,22 00:00
    public static LocalDateTime getDayStart(LocalDateTime time) {
        return time.withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    //获取一天的结束时间，2017,7,22 23:59:59.999999999
    public static LocalDateTime getDayEnd(LocalDateTime time) {
        return time.withHour(23)
                .withMinute(59)
                .withSecond(59)
                .withNano(999999999);
    }

    /**
     * 当前时间 - now -获取不同格式时间
     */
    //获取当前当前时间年（yyyy）
    public static String getYear() {
        return formatNow(YEAR);
    }
    //获取当前当前时间年月（yyyy-MM）
    public static String getYearMonth() {
        return formatNow(YEAR_MONTH);
    }
    //获取当前当前时间年月日（yyyy-MM-dd）
    public static String getYearMonthDay() {
        return formatNow(YEAR_MONTH_DAY);
    }
    //获取当前当前时间年月日时（yyyy-MM-dd HH）
    public static String getYearMonthDayHour() {
        return formatNow(DATE_HOUR);
    }
    /**
     * 获取当前时间字符串，格式（yyyyMMddHHmmss）
     * @return
     */
    public static String getTimeStr(){
        return formatNow(DATE_TIME_STR);
    }
    //获取当前时间一年前，格式yyyy-MM
    public static String getAgoYearMonth(){
        return formatTime(LocalDateTime.now().minus(1,ChronoUnit.YEARS), YEAR_MONTH);
    }


    /**
     * 获取当前时间一天前，格式（yyyy-MM-dd）
     * @return 2021-12-29 --> 2021-12-28
     */
    public static String getAgoYearMonthDay(){
        return formatTime(LocalDateTime.now().minus(1,ChronoUnit.DAYS), YEAR_MONTH_DAY);
    }



    /**
     * 当前时间 - now -获取列表
     * 年->月列表
     * 月->日列表
     * 日->小时列表
     */

    /**
     * 获取当前时间一年前每个月，格式yyyy-MM
     * 当前时间2021-12-02 14:56:00
     * ["2020-12","2021-01","2021-02","2021-03"..."2021-07","2021-08","2021-09","2021-10","2021-11"]
     * @return
     */
    public static List<String> getMonthListByAYearAgo(){
        List<String> list = new ArrayList<>();
        for (int i = 12; i > 0; i--) {
            list.add(formatTime(LocalDateTime.now().minus(i,ChronoUnit.MONTHS), YEAR_MONTH));
        }
        return list;
    }

    /**
     * 本年-月列表
     * ["2021-01","2021-02","2021-03"..."2021-11","2021-12"]
     * @return
     */
    public static List<String> getMonthList(){
        LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
        LocalDate end = LocalDate.now().with(TemporalAdjusters.lastDayOfYear());
        List<String> list = getPeriod(start, end, 2);
        return list;
    }

    /**
     * 本年-季度列表
     * ["2021-1","2021-2","2021-3","2021-4"]
     * @return
     */
    public static List<String> getQuarterList(){
        LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfYear());
        LocalDate end = LocalDate.now().with(TemporalAdjusters.lastDayOfYear());
        List<String> list = getPeriod(start, end, 3);
        return list;
    }

    /**
     * 本月-日列表
     *["2021-12-01","2021-12-02","2021-12-03"..."2021-12-31"]
     * @return
     */
    public static List<String> getDayList(){
        LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        LocalDate end = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        List<String> list = getPeriod(start, end, 0);
        return list;
    }

    /**
     * 本日-时列表
     *
     * @return
     */
    public static List<String> getHourList(){
        LocalDate start = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
        LocalDate end = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
        List<String> list = getPeriod(start, end, 0);
        return list;
    }




    //获取当前日期减去一个数,根据field不同减不同值,field参数为ChronoUnit.*  获取当前时间一年前，格式yyyy-MM
    public static String minuPattern(long number, TemporalUnit field, String pattern){
        return formatTime(LocalDateTime.now().minus(number,field), pattern);
    }

    /**
     * 根据时间段获取 指定类型列表
     * [@param] start
     * [@param] end
     * [@param] unit 天:0 周:1 月：2 季：3 半年：4 年：5
     * [@return]天: 2019-07-11 周：2019-52 月：2019-07 季：2019-4 半年：2019-2 年：2019
     */
    public static List<String> getPeriod(LocalDate start,LocalDate end,int unit) {
        if (start.compareTo(end) > 0) {
            throw new DateTimeException("start cannot be greater than the end");
        }
        List<String> list = new ArrayList<>();
        switch (unit) {
            case 0:
                getDays(start,end,list);
                break;
            case 1:
                getWeeks(start,end,list);
                break;
            case 2:
                getMonths(start,end,list);
                break;
            case 3:
                getQuarters(start,end,list);
                break;
            case 4:
                getHalfYears(start,end,list);
                break;
            case 5:
                getYears(start,end,list);
                break;
            default:
                break;
        }
        return list;
    }

    // 获取天列表
    private static void getDays(LocalDate start, LocalDate end, List<String> list) {
        while (start.compareTo(end) <= 0) {
            list.add(start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            start = start.plusDays(1);
        }
    }
    // 获取周列表
    private static void getWeeks(LocalDate start, LocalDate end, List<String> list) {
        // 初始化 周 iso标准 起始周一 大于4天
        // WeekFields weekFields = WeekFields.ISO;
        // 初始化 第一天即第一周
        WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,1);
        while (start.compareTo(end) <= 0) {
            list.add(start.getYear()+"-"+start.get(weekFields.weekOfWeekBasedYear()));
            start = start.plusWeeks(1);
        }
    }
    // 获取月列表
    private static void getMonths(LocalDate start, LocalDate end, List<String> list) {
        while (start.getYear()*100+start.getMonthValue() <= end.getYear()*100+end.getMonthValue()) {
            list.add(start.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            start = start.plusMonths(1);
        }
    }
    // 获取季列表
    private static void getQuarters(LocalDate start, LocalDate end, List<String> list) {
        while (start.getYear()*10+((int)Math.ceil(start.getMonthValue() / 3.0)) <= end.getYear()*10+((int)Math.ceil(end.getMonthValue() / 3.0))) {
            String quarter = start.getYear() +"-"+ ((int)Math.ceil(start.getMonthValue() / 3.0));
            if (!list.contains(quarter)) {
                list.add(quarter);
            }
            start = start.plusMonths(1);
        }
    }
    // 获取半年列表
    private static void getHalfYears(LocalDate start, LocalDate end, List<String> list) {
        while (start.getYear()*10+((int)Math.ceil(start.getMonthValue() / 6.0)) <= ((int)Math.ceil(end.getMonthValue() / 6.0))) {
            String quarter = start.getYear() +"-"+ ((int)Math.ceil(start.getMonthValue() / 6.0));
            if (!list.contains(quarter)) {
                list.add(quarter);
            }
            start = start.plusMonths(1);
        }
    }
    // 获取年列表
    private static void getYears(LocalDate start, LocalDate end, List<String> list) {
        while (start.getYear() <= end.getYear()) {
            list.add(start.getYear()+"");
            start = start.plusYears(1);
        }
    }

    /**
     * 传入日期参数，获得日期范围内的所有日期元素集合
     * @param start 开始日期
     * @param end 结束日期
     * @return
     * @throws Exception
     */
    public List<String> getDateStrList(Date start, Date end)  throws Exception {
        DateFormat formatDate =new SimpleDateFormat(YEAR_MONTH_DAY);
        List<String>  dateStrList = new ArrayList<String>();
        String startStr = formatDate.format(start);
        String endStr = formatDate.format(end);
        String endOneStr = formatDate.format(getAddOneDay(end)); //结束日期加1天
        if(startStr.equals(endStr)){
            dateStrList.add(startStr);
        }else{
            String nextDay = startStr;   //下一天
            Date cursorDay = start; //游标日期
            do{
                dateStrList.add(nextDay);
                Date addDate = getAddOneDay(cursorDay);
                nextDay = formatDate.format(addDate);
                cursorDay = addDate;
            }while(!nextDay.equals(endOneStr));
        }
        return dateStrList;
    }
    /**
     * 给传入日期加1天
     * @param dataStr
     * @return
     * @throws Exception
     */
    public Date getAddOneDay(Date dataStr) throws Exception {
        Calendar cal = Calendar.getInstance();
        cal.setTime(dataStr);
        cal.add(Calendar.DAY_OF_MONTH, 1);//增加1天
        Date addDate = cal.getTime();
        return addDate;
    }

    /**
     *
     * @param dataStr 2022-05-05T07:46:32+08:00
     * @return str 2022-05-05 07:46:32
     * @throws Exception
     */
    public static String getDateStrRemoveT(String dataStr) {
        DateFormat df = new SimpleDateFormat(DATE_TIME_T_STR);
        SimpleDateFormat df1 = new SimpleDateFormat (DATE_TIME_UK_STR, Locale.UK);
        DateFormat df2 = new SimpleDateFormat(DATE_TIME);
        Date date;
        Date date1;
        String dateStr;
        try {
            date = df.parse(dataStr);
            date1 = df1.parse(date.toString());
            dateStr = df2.format(date1);
        } catch (ParseException e) {
            throw new RuntimeException("Parse to remove time format exception with T");
        }
        return dateStr;
    }

    /**
     *
     * @param idCardTime
     * @return dateStr 2022-05-05
     */
    public static String getIdCardTime(String idCardTime) throws ParseException {
        SimpleDateFormat df = new SimpleDateFormat (ID_CARD_TIME);
        SimpleDateFormat df2 = new SimpleDateFormat (YEAR_MONTH_DAY);
        Date iDCardDate = df.parse(idCardTime);
        String dateStr = df2.format(iDCardDate);;
        return dateStr;
    }


    /**
     * @param str yyyy-MM-dd HH:mm:ss
     * @return Date
     */
    public static Date getStrCoverDate(String str) {
        return getStrCoverDate(str, DATE_TIME);
    }

    /**
     * @param str yyyy-MM-dd HH:mm:ss
     * @return Date
     */
    public static Date getStrCoverDate(String str, String format) {
        SimpleDateFormat sf = new SimpleDateFormat(format);
        Date date = null;
        try {
            //使用SimpleDateFormat的parse()方法生成Date
            date = sf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}